(#) features
**1)** Parallelization with SmallThreadPool - 1 pt.
Since rendering can be (and is almost always), a daunting process, parallelism is the first modificiation I made to darts.
I parallelized the image synthesis loop using SmallThreadPool library. Instead of iterating over all pixels
in a single nested loop, I partitioned independent blocks of pixels and distributed it across a collection of workers initialized to the number
of hardware threads on my CPU (20 in my case). Doing so cuts down render time by ~3x as demonstrated here.
**2)** Rendering using the Discovery Cluster - 1 pt.
We can still cut it down further thanks to Dartmouth's Discovery Cluster. I will skip over the details as implementation is "trivial" but I'm basically
running darts on the cluster with significantly more computational resource.
**3)** Intel's Open Image Denoiser - 2 pts.
This one was relatively challenging to implement only because the relevant documentations provided for Ubuntu is obsolete (e.g. packages don't exist in apt search).
Beyond that, it was a simple one-line function call once the library was wired up. I made a small helper denoise_with_oidn(Image3f &img) that wraps the API and we call
it right before darts perform a save operation.
I made clones of samplers inside each worker thread. Otherwise, our next1f/next2f() functions behave like a global randf(), effectively serializing
the threads on a single sampler. I found 128 to be a good spp to get a denoised image without the artifacts we get when denoising
a low spp image.
Fig. 1. At sufficiently low spp (e.g. 16 spp), you start to get the blotched look.
But for the sake of validation, we will render everything but the final render without this denoiser.
scene.cpp
denoise_oidn.h
denoise_oidn.cpp
**4)** Environment Map Emitter (with importance sampling) - 2 pts.
At any given point in time, our surroundings are rarely a single area light; most illuminants are objects that reflect
off of direct light sources. To "color" our scenes with such environments, I added support for environment maps that will
act both as a visible background and light source. We importance sample this emitter w.r.t. luminance over a given pixel of the envmap image.
**5)** Rough Conductor BSDF - 2 pts.
Spacesuits (and many other everyday items, not that spacesuits are one) are shiny, but they are not actually smooth
at the microscopic level. Instead, they're made of countless tiny perturbations with different orientations. Compared to a simple Phong or Blinn-Phong model,
the microfacet formulation enforces energy conservation. Whereas a classic Blinn/Phong model just adds an arbitrary specular lobe on top of a diffuse term,
a microfacet BRDF derives its specular term from the Trowbridge-Reitz GGX normal distribution function. Consequently,
changing roughness only redistributes the same incoming energy over directions instead of creating extra light.
Fig. 2. As observed, our microfacet model preserves the "brightness" and consequently, it looks more like a proper rough metal.
microfacet.cpp
**6)** Spectral Rendering - 8 pts.
Although most imaging pipelines are built around RGB, it is a crude approximation of how light and materials actually behave.
Many different spectra can collapse to the same RGB triplet, so compressing everything to three numbers throws away subtle visual
information, especially under non-white illumination or when dispersion is involved.
In my implementation, the path tracer operates directly in this spectral domain. Each camera ray carries a single wavelength λ sampled
uniformly between 400 nm and 700 nm, and all computations are done as functions of λ. This adds one extra dimension to the Monte Carlo
estimator and appears visually as colored noise at low sample counts. Only after tracing is complete does the Monte Carlo estimator
converge to the XYZ tristimulus values defined by the CIE 1931 color matching functions which are then mapped to RGB using the sRGB matrix (D65 white point).
Fig. 3. RGB vs spectral rendering vs wavelength-dependent IOR to demonstrate dispersion.
As expected, a wavelength-dependent IOR disperses rays going through our glass sphere and we get a slight magnification effect due to the different angles it
refracts through.
integrator.h/cpp
spectrum.h/cpp
PathTracerSpectralMIS.cpp
spectrum_data.cpp
ray.h
(#) final scene
“Entangled” -- final render for the competition. This scene is inspired by BT-encounters in Death Stranding.
(#) acknowledgementsCode/Theory:
Most of my algorithms are derived from Physically Based Rendering - From Theory to Implementation by Matt Pharr, Wenzel Jakob, Greg Humphreys
Hero Wavelength Spectral Sampling by Alexander Wilkie, Sehera Nawaz, Marc Droske, Andrea Weidlich, Johannes Hanika
https://momentsingraphics.de/SpectralRenderingOverview.html
Assets:
3D model of Franz Viehböck's Sokol Space Suit is courtesy of the Naturhistorisches Museum Wien
https://zachfox.photography/stories/mirrors-edge-catalyst-ansel-360-stereo/#x
https://sketchfab.com/3d-models/strand-1-4ca6639319a149d686d050a3f5ea3e02
https://www.thingiverse.com/thing:4039942
https://www.spacespheremaps.com/hdr-spheremaps/
(##)
addenum: a stretch goal was to implement heterogeneous participating media to add fog on the surface. It would've paired well with the environment map.